/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package fork;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import tal.drivechain.chain.AbortChainException;
import tal.drivechain.plugin.Channel;
import tal.drivechain.plugin.Module;
import tal.drivechain.module.xmlconfig.PropertyInfo;
import tal.drivechain.module.xmlconfig.ModuleInfo;
import tal.drivechain.variable.types.ArrayType;
import tal.drivechain.variable.types.DataType;
import tal.drivechain.variable.types.NumberType;
import tal.drivechain.variable.SetProperty;
import tal.drivechain.variable.Variable;

/**
 *
 * @author Main
 */
public class Inspector extends Module {
    private ModuleInfo modInfo = null;
    private Module module = null;

    @Override
    public void setupProperties() throws IllegalArgumentException, AbortChainException {
        setModule(props.getProperty("module"), null);
    }

    public void setModule(Object value, SetProperty.Flag flag) {
        if (value==null) {
            module = null;
            modInfo = null;
        } else {
            module = (Module)value;
            modInfo = (ModuleInfo)module.getNodeInfo();
        }
    } public Object getModule() { return module; }
    
    public void sendDescription() {
        if (modInfo==null)
            log("Can't get description. <module> is not set.", MSG.WARNING);
        else {
            Variable out = new Variable("description", DataType.STRING, modInfo.getDescription(), true);
            this.sendToOutputs(out, -1); 
        }
    }
    
    public void sendName() {
        if (modInfo==null)
            log("Can't get description. <module> is not set.", MSG.WARNING);
        else {
            Variable out = new Variable("name", DataType.STRING, module.getNodeClassName(), true);
            this.sendToOutputs(out, -1); 
        }
    }
    
    public void sendSyntax() {
        if (modInfo==null)
            log("Can't get description. <module> is not set.", MSG.WARNING);
        else {
            Variable out = new Variable("syntax", DataType.STRING, modInfo.getSyntax(), true);
            this.sendToOutputs(out, -1); 

        }
    }
    
    public void sendUsage() {
        if (modInfo==null)
            log("Can't get description. <module> is not set.", MSG.WARNING);
        else {
            String usage = modInfo.getUsage();
            if (usage==null) usage = "";
            Variable out = new Variable("usage", DataType.STRING, usage, true);
            this.sendToOutputs(out, -1); 
        }

    }
    
    public void sendPropertyHelp() {
        if (modInfo==null)
            log("Can't get property help. <module> is not set.", MSG.WARNING);
        String ret = "";
        for (PropertyInfo prop : modInfo.getProperties()) {
            String propHelp = "";
            if (prop.isOrdered()) propHelp = "(" + prop.getOrderIndex() + ") ";
            else propHelp = "(.) ";
            propHelp += prop.getName() + " (" + prop.getParser().getPropertyType() + "): " + prop.getDescription();
            String attributes = "";
            if (prop.isRepeatable()) attributes += "repeatable, ";
            if (prop.isOptional()) attributes += "optional (default: " + prop.getDefaultValueString() + "), ";
            if (module.isPropertySettable(prop.getName()))
                attributes += "settable, ";
            if (attributes.length()>0) propHelp += " (" + attributes.substring(0,attributes.length()-2) + ").";
            ret += propHelp + "\n";
        }
        Variable out = new Variable("propertyHelp", DataType.STRING, ret, true);
        sendToOutputs(out, -1);
    }

    public void sendPropertyParam(String name, String... parameters) {
        if (modInfo==null)
            log("Can't get description. <module> is not set.", MSG.WARNING);
        else {
            int idx = -1;

            for (PropertyInfo info : modInfo.getProperties()) {
                if (info.getName().equals(name)) {
                    idx = modInfo.getProperties().indexOf(info);
                    break;
                }
            }
            if (idx==-1) {
                log("Can't find property '" + name + "'", MSG.WARNING);
                return;
            }

            PropertyInfo info = modInfo.getProperties().get(idx);
            String fname = "prop";
                
            for (int i=1; i<parameters.length; i++) {
                String param = parameters[i];

                fname = fname + "$" + param;
                if (param.equals("name")) {
                    Variable out = new Variable(fname , DataType.STRING, info.getName(), true);
                    this.sendToOutputs(out, -1);
                } else if (param.equals("default")) {
                    Variable out = new Variable(fname , DataType.STRING, info.getDefaultValueString(), true);
                    this.sendToOutputs(out, -1);
                } else if (param.equals("description")) {
                    Variable out = new Variable(fname , DataType.STRING, info.getDescription(), true);
                    this.sendToOutputs(out, -1);
                } else if (param.equals("order")) {
                    Variable out = new Variable(fname, DataType.INT, info.getOrderIndex(), true);
                    this.sendToOutputs(out, -1);
                } else if (param.equals("isOrdered")) {
                    Variable out = new Variable(fname, DataType.BOOLEAN, info.isOrdered(), true);
                    this.sendToOutputs(out, -1);
                } else if (param.equals("isOptional")) {
                    Variable out = new Variable(fname, DataType.BOOLEAN, info.isOptional(), true);
                    this.sendToOutputs(out, -1);
                } else log("Unknown property info parameter: " + param, MSG.WARNING);
            }
        }
    }
    
    public void sendPropertiesList() {
        Variable out = new Variable("props", new ArrayType(DataType.STRING), modInfo.getProperties(), true);
        sendToOutputs(out, -1);
    }
    
    public void sendCommands() {
        List<String> commands = new ArrayList();
        for (Method m : module.getModuleCommands())
            commands.add(m.getName());
        Variable out = new Variable("commands", new ArrayType(DataType.STRING), commands, true);
        sendToOutputs(out, -1);
    }

    @Override
    protected void msgReceived(Variable in, long timestamp, Channel channel) {
    }
}
